﻿namespace KeRui.Upload
{
    using System;
    using System.Collections;
    using System.IO;
    using System.Reflection;
    using System.Text;

    internal class Multipart
    {
        private static byte[] sBoundary = Encoding.ASCII.GetBytes("boundary=");
        private static string sContentType = "multipart/form-data; boundary=";
        private static byte[] sCRLF = Encoding.ASCII.GetBytes("\r\n");
        private static byte[] sDashDash = Encoding.ASCII.GetBytes("--");
        private static byte[] sFileReplacement = Encoding.ASCII.GetBytes("Uploaded File At:");

        internal class Boundary
        {
            public static string GetContentType(Stream inStream)
            {
                return GetContentType(GetMultipartBoundary(inStream));
            }

            public static string GetContentType(byte[] inBoundary)
            {
                if ((inBoundary == null) || (inBoundary.Length <= 2))
                {
                    return "";
                }
                byte[] destinationArray = new byte[inBoundary.Length - 2];
                Array.Copy(inBoundary, 2, destinationArray, 0, inBoundary.Length - 2);
                inBoundary = destinationArray;
                return (Multipart.sContentType + Encoding.ASCII.GetString(inBoundary));
            }

            public static byte[] GetMultipartBoundary(Stream inStream)
            {
                SuperStream stream = new SuperStream(inStream);
                byte[] array = new byte[0];
                long num = 0L;
                long num2 = 0L;
                long num3 = 0L;
                bool flag = false;
                num = stream.FindStr(Multipart.sDashDash);
                if (num >= 0L)
                {
                    num2 = stream.FindStr(Multipart.sCRLF);
                    if (num2 < 0L)
                    {
                        return array;
                    }
                    if (num >= Multipart.sBoundary.Length)
                    {
                        stream.Position = num - Multipart.sBoundary.Length;
                        if (stream.EqualStr(Multipart.sBoundary))
                        {
                            flag = true;
                        }
                    }
                    stream.Position = num;
                    num3 = num2 - num;
                    if (flag)
                    {
                        num3 += 2L;
                    }
                    array = new byte[num3];
                    if (flag)
                    {
                        Multipart.sDashDash.CopyTo(array, 0);
                        stream.Read(array, 2, ((int) num3) - 2);
                        return array;
                    }
                    stream.Read(array, 0, (int) num3);
                }
                return array;
            }

            public static byte[] GetSafeMultipartBoundary(Stream inStream)
            {
                SuperStream stream = new SuperStream(inStream);
                byte[] multipartBoundary = GetMultipartBoundary(inStream);
                if (multipartBoundary.Length > 0x20)
                {
                    byte[] destinationArray = new byte[0x20];
                    Array.Copy(multipartBoundary, 0, destinationArray, 0, 0x20);
                    multipartBoundary = destinationArray;
                }
                stream.Position = 0L;
                if ((stream.FindStr(multipartBoundary) < 0L) && (multipartBoundary.Length > 2))
                {
                    byte[] buffer3 = new byte[multipartBoundary.Length - 2];
                    Array.Copy(multipartBoundary, 2, buffer3, 0, multipartBoundary.Length - 2);
                    multipartBoundary = buffer3;
                    stream.Position = 0L;
                    if (stream.FindStr(multipartBoundary) < 0L)
                    {
                        multipartBoundary = new byte[0];
                    }
                }
                return multipartBoundary;
            }
        }

        internal class Field
        {
            private ArrayList mAttributes;
            private ArrayList mData;
            private long mDataLen;
            private bool mDumpFiles;
            private string mFieldName;
            private byte[] mFileName;
            private string mMIMEType;
            private bool mReserialize;
            private KeRui.Upload.TempFile mTempFile;

            public Field(bool inDumpFiles, bool inReserializeFiles)
            {
                this.mDumpFiles = inDumpFiles;
                this.mReserialize = inReserializeFiles;
                this.mFileName = null;
                this.mFieldName = null;
                this.mMIMEType = null;
                this.mAttributes = new ArrayList();
                this.mData = new ArrayList();
                this.mTempFile = null;
                this.mDataLen = 0L;
            }

            public void AddAttribute(byte[] inAttribute, int inCodePage)
            {
                this.mAttributes.Add(inAttribute);
                this.ProcessAttribute(inAttribute, inCodePage);
                this.MakeTempFile();
            }

            public void AddData(byte[] inData)
            {
                this.mDataLen += inData.Length;
                this.mData.Add(inData);
                if (this.mTempFile != null)
                {
                    this.WriteData();
                }
                if ((this.mDumpFiles && (this.mTempFile == null)) && (this.mDataLen > 0x4000000L))
                {
                    Log.UniqueError("Large corrupt upload detected. Flushing data store.");
                    this.mData.Clear();
                }
            }

            public void AddData(SuperStream inStream, long inLen)
            {
                if (inLen > 0L)
                {
                    byte[] buffer = new byte[inLen];
                    inStream.Read(buffer, 0, (int) inLen);
                    this.AddData(buffer);
                }
            }

            public void ClearData()
            {
                this.mAttributes.Clear();
                this.mData.Clear();
            }

            public void ClearFiles()
            {
                this.mAttributes.Clear();
                if (this.mTempFile != null)
                {
                    this.mTempFile.Dispose();
                }
                this.mTempFile = null;
            }

            public void Finish()
            {
                if (this.mTempFile != null)
                {
                    this.mTempFile.CloseStream();
                }
            }

            private byte[] GetAttributeValue(SuperStream inStream, string inValueName)
            {
                byte[] bytes = Encoding.ASCII.GetBytes(inValueName);
                byte[] buffer = null;
                long num = inStream.FindStr(bytes);
                num = inStream.FindStr(Encoding.ASCII.GetBytes("="));
                num = inStream.FindStr(Encoding.ASCII.GetBytes("\""));
                if (num < 0L)
                {
                    return null;
                }
                long num2 = inStream.FindStr(Encoding.ASCII.GetBytes("\";"));
                if (num2 < 0L)
                {
                    num2 = inStream.Length - 1L;
                }
                num += 1L;
                num2 -= 1L;
                long num3 = (num2 - num) + 1L;
                if (num3 < 0L)
                {
                    return null;
                }
                buffer = new byte[num3];
                inStream.Position = num;
                inStream.Read(buffer, 0, (int) num3);
                return buffer;
            }

            private void MakeTempFile()
            {
                if ((this.mDumpFiles && (this.mFileName != null)) && (this.mTempFile == null))
                {
                    this.mTempFile = new KeRui.Upload.TempFile();
                    if (!this.mTempFile.Writable)
                    {
                        this.mDumpFiles = false;
                        this.mTempFile = null;
                        Log.UniqueError("Unable to create temporary file. ");
                    }
                }
            }

            private void ProcessAttribute(byte[] inData, int inCodePage)
            {
                SuperStream inStream = new SuperStream(new MemoryStream(inData));
                string str = inStream.ToString().ToLower();
                if (str.StartsWith("content-disposition:"))
                {
                    this.mFieldName = HTTPUtils.Decode(this.GetAttributeValue(inStream, "name"), inCodePage);
                    this.mFileName = this.GetAttributeValue(inStream, "filename");
                }
                else if (str.StartsWith("content-type:"))
                {
                    this.mMIMEType = str.Substring(str.IndexOf(":") + 1).Trim();
                }
            }

            public void Serialize(Stream inStream)
            {
                byte[] bytes;
                int num;
                for (num = 0; num < this.mAttributes.Count; num++)
                {
                    bytes = (byte[]) this.mAttributes[num];
                    inStream.Write(bytes, 0, bytes.Length);
                    inStream.Write(Multipart.sCRLF, 0, Multipart.sCRLF.Length);
                }
                inStream.Write(Multipart.sCRLF, 0, Multipart.sCRLF.Length);
                if (this.mData.Count > 0)
                {
                    for (num = 0; num < this.mData.Count; num++)
                    {
                        bytes = (byte[]) this.mData[num];
                        inStream.Write(bytes, 0, bytes.Length);
                        this.mData[num] = null;
                    }
                }
                else if (this.mTempFile != null)
                {
                    if (this.mReserialize)
                    {
                        FileUtils.StreamToStream(this.mTempFile.FileStream, inStream);
                    }
                    else
                    {
                        inStream.Write(Multipart.sFileReplacement, 0, Multipart.sFileReplacement.Length);
                        bytes = Encoding.ASCII.GetBytes(this.mTempFile.Path);
                        inStream.Write(bytes, 0, bytes.Length);
                    }
                }
                inStream.Write(Multipart.sCRLF, 0, Multipart.sCRLF.Length);
            }

            private void WriteData()
            {
                try
                {
                    FileStream fileStream = this.mTempFile.FileStream;
                    for (int i = 0; i < this.mData.Count; i++)
                    {
                        byte[] buffer = (byte[]) this.mData[i];
                        fileStream.Write(buffer, 0, buffer.Length);
                    }
                    this.mData.Clear();
                }
                catch
                {
                }
            }

            public string FieldName
            {
                get
                {
                    return this.mFieldName;
                }
            }

            public byte[] FileName
            {
                get
                {
                    return this.mFileName;
                }
            }

            public bool IsFileField
            {
                get
                {
                    return (this.mFileName != null);
                }
            }

            public string MIMEType
            {
                get
                {
                    return this.mMIMEType;
                }
            }

            public KeRui.Upload.TempFile TempFile
            {
                get
                {
                    return this.mTempFile;
                }
            }
        }

        internal class Form
        {
            private byte[] mBoundaryFull;
            private byte[] mBoundarySafe;
            private byte[] mBuffer;
            private int mCodePage;
            private Multipart.Field mCurrentItem;
            private bool mDumpFiles;
            private ArrayList mFields;
            private bool mOptimize;
            private bool mReserialize;
            private State mState;

            public Form(int inCodePage, bool inDumpFiles, bool inReserializeFiles, bool inOptimize)
            {
                this.mCodePage = inCodePage;
                this.mDumpFiles = inDumpFiles;
                this.mReserialize = inReserializeFiles;
                this.mOptimize = inOptimize;
                this.mFields = new ArrayList();
                this.mBoundaryFull = null;
                this.mBoundarySafe = null;
                this.mBuffer = null;
                this.mState = State.GetBoundary;
                this.mCurrentItem = null;
            }

            private void AddBuffers(byte[] inBuffer)
            {
                if (this.mBuffer == null)
                {
                    this.mBuffer = inBuffer;
                }
                else
                {
                    byte[] array = new byte[this.mBuffer.Length + inBuffer.Length];
                    this.mBuffer.CopyTo(array, 0);
                    inBuffer.CopyTo(array, this.mBuffer.Length);
                    this.mBuffer = array;
                }
            }

            public void AddData(byte[] inBuffer)
            {
                bool flag = true;
                this.AddBuffers(inBuffer);
                SuperStream inStream = new SuperStream(new MemoryStream(this.mBuffer));
                if ((this.mOptimize && (this.mState == State.ReadData)) && this.IsAllData(this.mBoundarySafe, this.mBuffer, 0))
                {
                    this.CurrentField.AddData(this.mBuffer);
                    inStream.Position = inStream.Length;
                    flag = false;
                }
                while (flag)
                {
                    long position;
                    long num2;
                    switch (this.mState)
                    {
                        case State.Invalid:
                        {
                            inStream.Position = 0L;
                            flag = false;
                            continue;
                        }
                        case State.GetBoundary:
                        {
                            this.mBoundaryFull = Multipart.Boundary.GetMultipartBoundary(inStream);
                            this.mBoundarySafe = Multipart.Boundary.GetSafeMultipartBoundary(inStream);
                            flag = (this.mBoundaryFull.Length > 0) && (this.mBoundarySafe.Length > 0);
                            inStream.Position = 0L;
                            if (flag)
                            {
                                this.mState = State.FindFirstBoundary;
                            }
                            continue;
                        }
                        case State.FindFirstBoundary:
                        {
                            num2 = inStream.FindStr(this.mBoundarySafe);
                            this.mState = (num2 >= 0L) ? State.FindStartOfData : State.Invalid;
                            continue;
                        }
                        case State.FindStartOfData:
                            position = inStream.Position;
                            if (inStream.FindStr(Multipart.sCRLF) < position)
                            {
                                goto Label_021C;
                            }
                            break;

                        case State.ReadAttribute:
                            position = inStream.Position;
                            num2 = inStream.FindStr(Multipart.sCRLF);
                            if (num2 != position)
                            {
                                goto Label_022B;
                            }
                            goto Label_01AB;

                        case State.ReadData:
                            position = inStream.Position;
                            num2 = inStream.FindStr(this.mBoundarySafe);
                            if (num2 < position)
                            {
                                goto Label_028F;
                            }
                            goto Label_01B7;

                        default:
                        {
                            continue;
                        }
                    }
                    this.mState = State.ReadAttribute;
                    continue;
                Label_01AB:
                    this.mState = State.ReadData;
                    continue;
                Label_01B7:
                    inStream.Position = position;
                    num2 -= position + 2L;
                    if (num2 > 0L)
                    {
                        this.CurrentField.AddData(inStream, num2);
                    }
                    this.CurrentField.Finish();
                    inStream.Position += this.mBoundarySafe.Length + 2;
                    this.mCurrentItem = null;
                    this.mState = State.FindStartOfData;
                    continue;
                Label_021C:
                    flag = false;
                    inStream.Position = position;
                    continue;
                Label_022B:
                    if (num2 > position)
                    {
                        byte[] buffer = new byte[num2 - position];
                        inStream.Position = position;
                        inStream.Read(buffer, 0, buffer.Length);
                        inStream.Position += 2L;
                        this.CurrentField.AddAttribute(buffer, this.mCodePage);
                    }
                    else
                    {
                        flag = false;
                        inStream.Position = position;
                    }
                    continue;
                Label_028F:
                    inStream.Position = position;
                    num2 = ((inStream.Length - position) - this.mBoundarySafe.Length) - 2L;
                    if (num2 > 0L)
                    {
                        this.CurrentField.AddData(inStream, num2);
                    }
                    flag = false;
                }
                this.TidyBuffers((int) inStream.Position);
            }

            public void Clear()
            {
                this.ClearData();
                this.ClearFiles();
            }

            public void ClearData()
            {
                for (int i = 0; i < this.mFields.Count; i++)
                {
                    ((Multipart.Field) this.mFields[i]).ClearData();
                }
            }

            public void ClearFiles()
            {
                for (int i = 0; i < this.mFields.Count; i++)
                {
                    ((Multipart.Field) this.mFields[i]).ClearFiles();
                }
            }

            ~Form()
            {
                this.ClearData();
                this.ClearFiles();
            }

            private void Finish()
            {
                if (this.mCurrentItem != null)
                {
                    this.mCurrentItem.Finish();
                    this.mCurrentItem = null;
                }
            }

            public byte[] GetData(int inExpectedSize)
            {
                if (!(!this.mDumpFiles || this.mReserialize))
                {
                    inExpectedSize = 0;
                }
                this.Finish();
                MemoryStream inStream = new MemoryStream(inExpectedSize);
                this.Serialize(inStream);
                inStream.Close();
                return inStream.GetBuffer();
            }

            private bool IsAllData(byte[] inBoundary, byte[] inBuffer, int inStart)
            {
                int length = inBoundary.Length;
                int index = 0;
                while (index < length)
                {
                    if (inBoundary[index] != 0x2d)
                    {
                        break;
                    }
                    index++;
                }
                if (index < 5)
                {
                    return false;
                }
                length = inBuffer.Length;
                if (length < 10)
                {
                    return false;
                }
                int num3 = length - 2;
                int num4 = inStart + 2;
                while (num4 < num3)
                {
                    if (inBuffer[num4] != 0x2d)
                    {
                        num4 += index;
                    }
                    else
                    {
                        if ((inBuffer[num4 + 1] == 0x2d) && (inBuffer[num4 + 2] == 0x2d))
                        {
                            return false;
                        }
                        if ((inBuffer[num4 - 1] == 0x2d) && (inBuffer[num4 - 2] == 0x2d))
                        {
                            return false;
                        }
                        num4 += index;
                    }
                }
                if (inBuffer[length - 1] == 0x2d)
                {
                    if (inBuffer[length - 2] == 0x2d)
                    {
                        return false;
                    }
                    if (inBuffer[length - 2] == 10)
                    {
                        return false;
                    }
                }
                else if (inBuffer[length - 1] == 10)
                {
                    if (inBuffer[length - 2] == 13)
                    {
                        return false;
                    }
                }
                else if (inBuffer[length - 1] == 13)
                {
                    return false;
                }
                return true;
            }

            public void Serialize(Stream inStream)
            {
                if (this.IsMultipart)
                {
                    for (int i = 0; i < this.mFields.Count; i++)
                    {
                        inStream.Write(this.mBoundaryFull, 0, this.mBoundaryFull.Length);
                        inStream.Write(Multipart.sCRLF, 0, Multipart.sCRLF.Length);
                        ((Multipart.Field) this.mFields[i]).Serialize(inStream);
                    }
                    inStream.Write(this.mBoundaryFull, 0, this.mBoundaryFull.Length);
                    inStream.Write(Multipart.sDashDash, 0, Multipart.sDashDash.Length);
                    inStream.Write(Multipart.sCRLF, 0, Multipart.sCRLF.Length);
                }
                else if (this.mBuffer != null)
                {
                    inStream.Write(this.mBuffer, 0, this.mBuffer.Length);
                }
            }

            private void TidyBuffers(int inBytesUsed)
            {
                byte[] destinationArray = null;
                int length = this.mBuffer.Length - inBytesUsed;
                if (length > 0)
                {
                    destinationArray = new byte[length];
                    Array.Copy(this.mBuffer, inBytesUsed, destinationArray, 0, length);
                }
                this.mBuffer = destinationArray;
            }

            public string ContentType
            {
                get
                {
                    return Multipart.Boundary.GetContentType(this.mBoundaryFull);
                }
            }

            public int Count
            {
                get
                {
                    return this.mFields.Count;
                }
            }

            private Multipart.Field CurrentField
            {
                get
                {
                    if (this.mCurrentItem == null)
                    {
                        this.mCurrentItem = new Multipart.Field(this.mDumpFiles, this.mReserialize);
                        this.mFields.Add(this.mCurrentItem);
                    }
                    return this.mCurrentItem;
                }
            }

            public byte[] CurrentFile
            {
                get
                {
                    if (this.Count > 0)
                    {
                        return this[this.Count - 1].FileName;
                    }
                    return new byte[0];
                }
            }

            public bool IsMultipart
            {
                get
                {
                    return ((this.mState != State.Invalid) && (this.mState != State.GetBoundary));
                }
            }

            public Multipart.Field this[int inIndex]
            {
                get
                {
                    return (Multipart.Field) this.mFields[inIndex];
                }
            }

            public static string KeyName
            {
                get
                {
                    return "WebSupergoo.Multipart.Form";
                }
            }

            private enum State
            {
                Invalid,
                GetBoundary,
                FindFirstBoundary,
                FindStartOfData,
                ReadAttribute,
                ReadData
            }
        }
    }
}

